package com.smart.community.property.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.smart.community.commons.result.PageResult;
import com.smart.community.commons.result.Result;
import com.smart.community.property.dto.RepairOrderDTO;
import com.smart.community.property.service.IPropertyService;
import com.smart.community.property.service.IRepairOrderService;
import com.smart.community.property.vo.RepairOrderVO;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.property.dto.RatingDTO;
import com.smart.community.commons.annotation.ApiLog;
import com.smart.community.commons.enums.ApiLogOperationType;

/**
 * 维修工单管理控制器
 * 
 * 严格按照《Java后端SpringBoot代码开发规范.md》权威标准实现：
 * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
 * - 移除Controller层log.error：避免日志级别错误
 * - 详细的日志记录，包括开始、成功状态
 * - 统一的返回格式，提供用户友好的错误提示
 * - 完善的权限验证和业务逻辑验证
 * - 完整的JavaDoc注释和Swagger文档
 * 
 * @author Wu.Liang
 * @since 2025-06-26
 * @version 4.0.0
 */
@Slf4j
@RestController
@RequestMapping("/property/repair-orders")
@Tag(name = "维修工单管理", description = "维修工单的创建、分配、查询、统计等接口")
public class RepairOrderController {

    @Autowired
    private IPropertyService propertyService;
    
    @Autowired
    private IRepairOrderService repairOrderService;

    /**
     * 创建维修工单
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 记录完整的操作日志，包括开始、成功状态
     * 
     * @param repairOrderDTO 维修工单DTO
     * @return 创建结果
     * @throws Exception 统一异常
     */
    @PostMapping
    @Operation(summary = "创建维修工单", description = "创建新的维修工单")
    @ApiLog(
        logTitle = "创建维修工单",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.ADD
    )
    public Result<Long> createRepairOrder(@RequestBody @Valid RepairOrderDTO repairOrderDTO) throws Exception {
        log.info("开始创建维修工单，用户ID: {}, 社区ID: {}, 报修类型: {}, 紧急程度: {}", 
                repairOrderDTO.getUserId(), repairOrderDTO.getCommunityId(), 
                repairOrderDTO.getRepairType(), repairOrderDTO.getUrgencyLevel());
        
        // 业务验证：检查必要参数
        if (repairOrderDTO.getUserId() == null) {
            log.warn("创建维修工单失败，用户ID不能为空");
            return Result.fail("用户ID不能为空");
        }
        if (repairOrderDTO.getCommunityId() == null) {
            log.warn("创建维修工单失败，社区ID不能为空");
            return Result.fail("社区ID不能为空");
        }
        
        Long orderId = propertyService.submitRepairOrder(repairOrderDTO);
        
        log.info("维修工单创建成功，工单ID: {}, 用户ID: {}, 社区ID: {}", 
                orderId, repairOrderDTO.getUserId(), repairOrderDTO.getCommunityId());
        return Result.success("维修工单创建成功", orderId);
    }


    /**
     * 分配维修工单
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 增加对null值的详细检查
     * - 提供具体的错误原因
     * 
     * @param orderId 工单ID
     * @param repairmanId 维修人员ID
     * @param remark 分配备注
     * @return 分配结果
     * @throws Exception 统一异常
     */
    @PutMapping("/{orderId}/assign")
    @Operation(summary = "分配维修工单", description = "将工单分配给维修人员")
    @ApiLog(
        logTitle = "分配维修工单",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.UPDATE
    )
    public Result<Boolean> assignRepairOrder(
            @Parameter(description = "工单ID") @PathVariable Long orderId,
            @Parameter(description = "维修人员ID") @RequestParam Long repairmanId,
            @Parameter(description = "分配备注") @RequestParam(required = false) String remark) throws Exception {
        // 参数验证
        if (orderId == null) {
            log.warn("分配维修工单失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        if (repairmanId == null) {
            log.warn("分配维修工单失败，维修人员ID不能为空");
            return Result.fail("维修人员ID不能为空");
        }
        
        log.info("开始分配维修工单，工单ID: {}, 维修人员ID: {}, 备注: {}", orderId, repairmanId, remark);
        
        boolean success = propertyService.assignRepairOrder(orderId, repairmanId, remark);
        
        if (success) {
            log.info("维修工单分配成功，工单ID: {}, 维修人员ID: {}", orderId, repairmanId);
            return Result.success("工单分配成功", true);
        } else {
            log.warn("维修工单分配失败，工单ID: {}, 维修人员ID: {}", orderId, repairmanId);
            return Result.fail("工单分配失败");
        }
    }


    /**
     * 分页查询维修工单列表
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 使用SecurityUtils.getCurrentUserId()获取当前用户ID
     * - 进行完整的权限验证和参数验证
     * - 支持多种查询条件筛选
     * 
     * @param current 当前页
     * @param size 每页大小
     * @param communityId 社区ID
     * @param status 工单状态
     * @param repairType 维修类型
     * @param urgencyLevel 紧急程度
     * @param keyword 关键词（工单号、标题、描述）
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 分页查询结果
     * @throws Exception 统一异常
     */
    @GetMapping
    @Operation(summary = "分页查询维修工单列表", description = "支持多种条件筛选的维修工单分页查询")
    public Result<PageResult<RepairOrderVO>> getRepairOrderList(
            @Parameter(description = "当前页") @RequestParam(defaultValue = "1") Integer current,
            @Parameter(description = "每页大小") @RequestParam(defaultValue = "20") Integer size,
            @Parameter(description = "社区ID") @RequestParam(required = false) Long communityId,
            @Parameter(description = "工单状态") @RequestParam(required = false) Integer status,
            @Parameter(description = "维修类型") @RequestParam(required = false) Integer repairType,
            @Parameter(description = "紧急程度") @RequestParam(required = false) Integer urgencyLevel,
            @Parameter(description = "关键词") @RequestParam(required = false) String keyword,
            @Parameter(description = "开始时间") @RequestParam(required = false) String startTime,
            @Parameter(description = "结束时间") @RequestParam(required = false) String endTime,
            @Parameter(description = "房户ID列表，多个用逗号分隔") @RequestParam(required = false) String householdIds) throws Exception {
        
        // 用户登录状态检查
        Long userId = SecurityUtils.getCurrentUserId();
        if (userId == null) {
            log.warn("分页查询维修工单列表失败，用户未登录");
            return Result.fail("用户未登录");
        }
        
        // 分页参数验证
        if (current == null || current < 1) {
            current = 1;
        }
        if (size == null || size < 1 || size > 100) {
            size = 20;
        }
        
        // 处理householdIds参数
        List<Long> householdIdList = null;
        if (householdIds != null && !householdIds.trim().isEmpty()) {
            try {
                householdIdList = new ArrayList<>();
                String[] ids = householdIds.split(",");
                for (String id : ids) {
                    if (id.trim().matches("\\d+")) {
                        householdIdList.add(Long.parseLong(id.trim()));
                    }
                }
                log.info("设置房户ID列表筛选条件: {}", householdIdList);
            } catch (Exception e) {
                log.warn("解析householdIds参数失败: {}, 忽略该参数", householdIds);
            }
        }
        
        log.info("开始分页查询维修工单列表，用户ID: {}, 当前页: {}, 每页大小: {}, 社区ID: {}, 状态: {}, 维修类型: {}, 紧急程度: {}, 关键词: {}, 房户ID列表: {}", 
                userId, current, size, communityId, status, repairType, urgencyLevel, keyword, householdIdList);
        
        // 调用Service层进行分页查询
        PageResult<RepairOrderVO> result = repairOrderService.pageRepairOrders(current, size, communityId, status, householdIdList);
        
        log.info("分页查询维修工单列表成功，用户ID: {}, 总记录数: {}, 当前页记录数: {}, 总页数: {}", 
                userId, result.getTotal(), result.getRecords().size(), result.getPages());
        return Result.success("查询成功", result);
    }



    /**
     * 更新工单状态
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 增加对状态值的验证
     * - 提供具体的错误原因
     * 
     * @param orderId 工单ID
     * @param status 状态
     * @param remark 备注
     * @return 更新结果
     * @throws Exception 统一异常
     */
    @PutMapping("/{orderId}/status")
    @Operation(summary = "更新工单状态", description = "更新维修工单的处理状态")
    @ApiLog(
        logTitle = "更新工单状态",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.UPDATE
    )
    public Result<Boolean> updateRepairOrderStatus(
            @Parameter(description = "工单ID") @PathVariable Long orderId,
            @Parameter(description = "状态：1-待受理，2-已受理，3-维修中，4-已完成，5-已取消") @RequestParam Integer status,
            @Parameter(description = "备注") @RequestParam(required = false) String remark) throws Exception {
        // 参数验证
        if (orderId == null) {
            log.warn("更新工单状态失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        if (status == null || status < 1 || status > 5) {
            log.warn("更新工单状态失败，状态值无效，工单ID: {}, 状态: {}", orderId, status);
            return Result.fail("状态值无效，必须是1-5之间的数字");
        }
        
        log.info("开始更新工单状态，工单ID: {}, 状态: {}, 备注: {}", orderId, status, remark);
        
        boolean success = propertyService.updateRepairOrderStatus(orderId, status, remark);
        
        if (success) {
            log.info("工单状态更新成功，工单ID: {}, 状态: {}", orderId, status);
            return Result.success("工单状态更新成功", true);
        } else {
            log.warn("工单状态更新失败，工单ID: {}, 状态: {}", orderId, status);
            return Result.fail("工单状态更新失败");
        }
    }

    /**
     * 获取报修类型列表
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 返回标准的报修类型列表
     * 
     * @return 报修类型列表
     * @throws Exception 统一异常
     */
    @GetMapping("/types")
    @Operation(summary = "获取报修类型列表", description = "获取系统支持的报修类型列表")
    public Result<List<Map<String, Object>>> getRepairTypes() throws Exception {
        log.info("开始获取报修类型列表");
        
        List<Map<String, Object>> types = new ArrayList<>();
        Map<String, Object> type1 = new HashMap<>();
        type1.put("value", 1);
        type1.put("label", "水电维修");
        types.add(type1);
        
        Map<String, Object> type2 = new HashMap<>();
        type2.put("value", 2);
        type2.put("label", "门窗维修");
        types.add(type2);
        
        Map<String, Object> type3 = new HashMap<>();
        type3.put("value", 3);
        type3.put("label", "电梯维修");
        types.add(type3);
        
        Map<String, Object> type4 = new HashMap<>();
        type4.put("value", 4);
        type4.put("label", "消防维修");
        types.add(type4);
        
        Map<String, Object> type5 = new HashMap<>();
        type5.put("value", 5);
        type5.put("label", "其他");
        types.add(type5);
        
        log.info("报修类型列表获取成功，类型数量: {}", types.size());
        return Result.success("获取报修类型列表成功", types);
    }

    /**
     * 获取工单详情
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 增加对工单存在性的验证
     * - 记录详细的查询日志
     * 
     * @param orderId 工单ID
     * @return 工单详情
     * @throws Exception 统一异常
     */
    @GetMapping("/{orderId}")
    @Operation(summary = "获取工单详情", description = "获取指定工单的详细信息")
    public Result<RepairOrderVO> getRepairOrderDetail(@Parameter(description = "工单ID") @PathVariable Long orderId) throws Exception {
        // 参数验证
        if (orderId == null) {
            log.warn("获取工单详情失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        
        log.info("开始获取工单详情，工单ID: {}", orderId);
        
        RepairOrderVO detail = propertyService.getRepairOrderDetail(orderId);
        
        if (detail == null) {
            log.warn("工单详情不存在，工单ID: {}", orderId);
            return Result.fail("工单不存在");
        }
        
        log.info("获取工单详情成功，工单ID: {}, 状态: {}, 用户ID: {}", 
                orderId, detail.getStatus(), detail.getUserId());
        return Result.success("查询成功", detail);
    }


    /**
     * 取消工单
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 增加对取消原因的验证
     * - 提供具体的错误原因
     * 
     * @param orderId 工单ID
     * @param reason 取消原因
     * @return 取消结果
     * @throws Exception 统一异常
     */
    @PutMapping("/{orderId}/cancel")
    @Operation(summary = "取消工单", description = "取消维修工单")
    @ApiLog(
        logTitle = "取消维修工单",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.UPDATE
    )
    public Result<Boolean> cancelRepairOrder(
            @Parameter(description = "工单ID") @PathVariable Long orderId,
            @Parameter(description = "取消原因") @RequestParam String reason) throws Exception {
        // 参数验证
        if (orderId == null) {
            log.warn("取消工单失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        if (reason == null || reason.trim().isEmpty()) {
            log.warn("取消工单失败，取消原因不能为空，工单ID: {}", orderId);
            return Result.fail("取消原因不能为空");
        }
        
        log.info("开始取消工单，工单ID: {}, 原因: {}", orderId, reason);
        
        boolean success = propertyService.updateRepairOrderStatus(orderId, 5, "取消原因：" + reason);
        
        if (success) {
            log.info("工单取消成功，工单ID: {}, 原因: {}", orderId, reason);
            return Result.success("工单取消成功", true);
        } else {
            log.warn("工单取消失败，工单ID: {}, 原因: {}", orderId, reason);
            return Result.fail("工单取消失败");
        }
    }

    /**
     * 完成工单
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 增加对维修结果的验证
     * - 提供具体的错误原因
     * 
     * @param orderId 工单ID
     * @param result 维修结果
     * @param remark 完成备注
     * @return 完成结果
     * @throws Exception 统一异常
     */
    @PutMapping("/{orderId}/complete")
    @Operation(summary = "完成工单", description = "标记维修工单为已完成")
    @ApiLog(
        logTitle = "完成工单",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.UPDATE
    )
    public Result<Boolean> completeRepairOrder(
            @Parameter(description = "工单ID") @PathVariable Long orderId,
            @Parameter(description = "维修结果") @RequestParam String result,
            @Parameter(description = "完成备注") @RequestParam(required = false) String remark) throws Exception {
        // 参数验证
        if (orderId == null) {
            log.warn("完成工单失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        if (result == null || result.trim().isEmpty()) {
            log.warn("完成工单失败，维修结果不能为空，工单ID: {}", orderId);
            return Result.fail("维修结果不能为空");
        }
        
        log.info("开始完成工单，工单ID: {}, 维修结果: {}, 备注: {}", 
                orderId, result, remark);
        
        boolean success = propertyService.completeRepairOrder(orderId, result, null, remark);
        
        if (success) {
            log.info("工单完成成功，工单ID: {}, 维修结果: {}", orderId, result);
            return Result.success("工单完成成功", true);
        } else {
            log.warn("工单完成失败，工单ID: {}, 维修结果: {}", orderId, result);
            return Result.fail("工单完成失败");
        }
    }

    /**
     * 提交满意度评分
     * 
     * 严格按照《Java后端SpringBoot代码开发规范.md》Controller规范：
     * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
     * - 移除Controller层log.error：避免日志级别错误
     * - 验证用户权限，只能对自己的报修记录评分
     * - 验证工单状态，只有已完成的工单才能评分
     * - 验证是否已经评分，防止重复评分
     * 
     * @param orderId 工单ID
     * @param ratingDTO 评分DTO
     * @return 评分结果
     * @throws Exception 统一异常
     */
    @PostMapping("/{orderId}/rating")
    @Operation(summary = "提交满意度评分", description = "移动端用户对已完成工单进行满意度评分")
    @ApiLog(
        logTitle = "工单评分",
        logType = 2,
        moduleName = "物业管理",
        operationType = ApiLogOperationType.UPDATE
    )
    public Result<Boolean> submitRating(
            @Parameter(description = "工单ID") @PathVariable Long orderId,
            @RequestBody @Valid RatingDTO ratingDTO) throws Exception {
        Long userId = SecurityUtils.getCurrentUserId();
        if (userId == null) {
            log.warn("提交满意度评分失败，用户未登录，工单ID: {}", orderId);
            return Result.fail("用户未登录");
        }
        
        // 参数验证
        if (orderId == null) {
            log.warn("提交满意度评分失败，工单ID不能为空");
            return Result.fail("工单ID不能为空");
        }
        if (ratingDTO == null || ratingDTO.getSatisfaction() == null) {
            log.warn("提交满意度评分失败，评分不能为空，工单ID: {}", orderId);
            return Result.fail("评分不能为空");
        }
        if (ratingDTO.getSatisfaction() < 1 || ratingDTO.getSatisfaction() > 5) {
            log.warn("提交满意度评分失败，评分无效，工单ID: {}, 评分: {}", orderId, ratingDTO.getSatisfaction());
            return Result.fail("评分必须是1-5之间的数字");
        }
        
        log.info("开始提交满意度评分，工单ID: {}, 用户ID: {}, 评分: {}", 
                orderId, userId, ratingDTO.getSatisfaction());
        
        // 验证用户权限，只能对自己的报修记录评分
        RepairOrderVO detail = repairOrderService.getRepairOrderDetail(orderId);
        if (detail == null) {
            log.warn("工单不存在，工单ID: {}", orderId);
            return Result.fail("工单不存在");
        }
        if (!detail.getUserId().equals(userId)) {
            log.warn("用户无权限对此工单进行评分，工单ID: {}, 用户ID: {}, 工单用户ID: {}", 
                    orderId, userId, detail.getUserId());
            return Result.fail("无权限对此工单进行评分");
        }
        
        // 验证工单状态，只有已完成的工单才能评分
        if (detail.getStatus() != 4) {
            log.warn("工单状态不允许评分，工单ID: {}, 状态: {}", orderId, detail.getStatus());
            return Result.fail("只有已完成的工单才能进行评分");
        }
        
        // 验证是否已经评分
        if (detail.getSatisfactionScore() != null && detail.getSatisfactionScore() > 0) {
            log.warn("工单已经评分，不能重复评分，工单ID: {}, 已有评分: {}", 
                    orderId, detail.getSatisfactionScore());
            return Result.fail("该工单已经评分，不能重复评分");
        }
        
        boolean success = repairOrderService.submitRating(orderId, ratingDTO.getSatisfaction());
        
        if (success) {
            log.info("满意度评分提交成功，工单ID: {}, 用户ID: {}, 评分: {}", 
                    orderId, userId, ratingDTO.getSatisfaction());
            return Result.success("评分提交成功", true);
        } else {
            log.warn("满意度评分提交失败，工单ID: {}, 用户ID: {}", orderId, userId);
            return Result.fail("评分提交失败");
        }
    }

    // ==================== 房户详情Tab页接口 ====================

    /**
     * 获取房户报修列表
     * 
     * @param householdId 房户ID
     * @param current 当前页
     * @param size 每页大小
     * @return 报修列表
     * @throws Exception 统一异常
     */
    @GetMapping("/household/{householdId}")
    @Operation(summary = "获取房户报修列表", description = "根据房户ID获取关联的报修工单列表")
    public Result<PageResult<RepairOrderVO>> getHouseholdRepairOrders(
            @Parameter(description = "房户ID") @PathVariable Long householdId,
            @Parameter(description = "当前页") @RequestParam(defaultValue = "1") Integer current,
            @Parameter(description = "每页大小") @RequestParam(defaultValue = "10") Integer size) throws Exception {
        log.info("获取房户报修列表，房户ID：{}，当前页：{}，每页大小：{}", householdId, current, size);
        
        PageResult<RepairOrderVO> result = repairOrderService.getHouseholdRepairOrders(householdId, current, size);
        
        log.info("获取房户报修列表成功，房户ID：{}，报修数量：{}", householdId, result.getTotal());
        return Result.success(result);
    }

}
